/*
 * udpcalcserv.cpp
 *
 *  Created on: 2011-3-31
 *      Author: zhuangmz
 */
#include	"../lib/unp.h"

void mzexit() {
	throw -1;
}

template <class ElemType>
class Stack
{
public:
	const static int MAXSIZE =1000;
	ElemType data[MAXSIZE];
	int top;
	void init();    // 初始化栈
	bool empty();    // 判断栈是否为空
	ElemType gettop();     // 读取栈顶元素(不出栈)
	void push(ElemType x); // 进栈
	ElemType pop();    // 出栈
};

template<class ElemType> void Stack<ElemType>::init()
{
	this->top = 0;
}

template<class ElemType> bool Stack<ElemType>::empty()
{
	return this->top == 0? true : false;
}

template<class ElemType> ElemType Stack<ElemType>::gettop()
{
	if(empty())
	{
		printf("Stack is NULL!\n");
		mzexit();
	}
	return this->data[this->top-1];
}

template<class ElemType> void Stack<ElemType>::push(ElemType x)
{
	if(this->top == MAXSIZE)
	{
		printf("Stack is FULL!\n");
		mzexit();
	}
	this->data[this->top] =x;
	this->top ++;
}

template<class ElemType> ElemType Stack<ElemType>::pop()
{
	if(this->empty())
	{
		printf("Stack is NULL!\n");
		mzexit();
	}

	ElemType e =this->data[this->top-1];
	this->top --;
	return e;
}

// 由后缀表达式字符串计算相应的中值表达式的值
double postfix_value(char post[]);

// 将数字字符串转变成相应的数字
double read_number(char str[],int *i);

// 将数字转变成相应的数字字符串
void read_char(char str[], double value, int len, int ndig);

// 求运算符优先级
int priority(char op);

bool isoperator(char op);

// 把中缀表达式转换为后缀表达式，返回后缀表达式的长度（包括空格）
void postfix(char pre[] ,char post[],int &n);

void
calc(int sockfd, SA *pcliaddr, socklen_t clilen)
{
	int			n;
	socklen_t	len;
	char		mesg[MAXLINE];
	double		expr_value;
	for ( ; ; ) {
		len = clilen;
		try
		{
			n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
			mesg[n - 1] = '\0';
			printf("%s\t=\t", mesg);
			mesg[n - 1] = '#';
			mesg[n] = '\0';
			n ++;
			char post[MAXLINE];
			int expr_len =0;    // 返回后缀表达式的长度
			postfix(mesg, post, expr_len);
			expr_value = postfix_value(post);
			read_char(mesg, expr_value, 15, 10);
			printf("%s\n", mesg);
			sendto(sockfd, mesg, n, 0, pcliaddr, len);
		}
		catch (int i)
		{
			mesg[0] = 'S';
			mesg[1] = 'O';
			mesg[2] = 'R';
			mesg[3] = 'R';
			mesg[4] = 'Y';
			mesg[5] = '\n';
			mesg[6] = '\0';
			printf("%s\n", mesg);
			sendto(sockfd, mesg, 6, 0, pcliaddr, len);
		}
	}
}

int
main(int argc, char **argv)
{
	int					sockfd;
	struct sockaddr_in	servaddr, cliaddr;

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port        = htons(SERV_PORT);
	bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
	calc(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
	return 0;
}

// 由后缀表达式字符串计算相应的中值表达式的值
double postfix_value(char post[])
{
	Stack<double> stack; // 操作数栈
	stack.init();
	int i=0 ;
	double x1,x2;
	while(post[i] !='#')
	{
		if(post[i] >='0' && post[i] <='9')
			stack.push(read_number(post,&i));
		else if(post[i] == ' ')
			i++;
		else if (post[i] =='+')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1+x2);
			i++;
		}
		else if (post[i] =='-')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1-x2);
			i++;
		}
		else if (post[i] =='*')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1*x2);
			i++;
		}
		else if (post[i] =='/')
		{
			x2 = stack.pop();
			x1 = stack.pop();
			stack.push(x1/x2);
			i++;
		}
	}
	return stack.gettop();
}

// 将数字字符串转变成相应的数字
double read_number(char str[],int *i)
{
	double x=0.0;
	int k = 0;
	while(str[*i] >='0' && str[*i]<='9') // 处理整数部分
	{
		x = x*10+(str[*i]-'0');
		(*i)++;
	}

	if(str[*i]=='.') // 处理小数部分
	{
		(*i)++;
		while(str[*i] >= '0'&&str[*i] <='9')
		{
			x = x * 10 + (str[*i]-'0');
			(*i)++;
			k++;
		}
	}
	while(k!=0)
	{
		x /= 10.0;
		k--;
	}
	return x;
}

// 求运算符优先级
int priority(char op)
{
	switch(op)
	{
		case '#':
			return -1;
		case '(':
			return 0;
		case '+':
		case '-':
			return 1;
		case '*':
		case '/':
			return 2;
		default :
			return -1;
	}
}

bool isoperator(char op)
{
	switch(op)
	{
	case '+':
	case '-':
	case '*':
	case '/':
		return 1;
	default :
		return 0;
	}
}

// 把中缀表达式转换为后缀表达式，返回后缀表达式的长度（包括空格）
void postfix(char pre[] ,char post[],int &n)
{
	int i = 0 ,j=0;
	Stack<char> stack;     // 使用的是类模板，在下篇文章给出
	stack.init();   // 初始化存储操作符的栈
	stack.push('#'); // 首先把结束标志‘#’放入栈底
	while(pre[i]!='#')
	{
		if((pre[i]>='0' && pre[i] <='9')||pre[i] =='.') // 遇到数字和小数点直接写入后缀表达式
		{
			post[j++] = pre[i];
			n++;
		}
		else if (pre[i]=='(') // 遇到“（”不用比较直接入栈
			stack.push(pre[i]);
		else if(pre[i] ==')') // 遇到右括号将其对应左括号后的操作符（操作符栈中的）全部 写入后缀表达式
		{
			while(stack.gettop()!='(')
			{
				post[j++] = stack.pop();
				n++;
			}
			stack.pop(); // 将“（”出栈，后缀表达式中不含小括号
		}
		else if (isoperator(pre[i]))
		{
			post[j++] = ' '; // 用空格分开操作数(
			n++;
			while(priority(pre[i]) <= priority(stack.gettop()))
			{
				// 当前的操作符小于等于栈顶操作符的优先级时，将栈顶操作符写入到后缀表达式，重复此过程
				post[j++] = stack.pop();
				n++;
			}
			stack.push(pre[i]); // 当前操作符优先级大于栈顶操作符的优先级，将该操作符入栈
		}
		i++;
	}
	while(stack.top) // 将所有还没有出栈的操作符加入后缀表达式
	{
		post[j++] = stack.pop();
		n++;
	}
}

// 将数字转变成相应的数字字符串
void read_char(char str[], double value, int len, int ndig)
{
	char *string;
	int sign;
	int dec;
	string = ecvt(value, ndig, &dec, &sign);
	int i=0;
		int index = 0;
		if (dec >= 1) {
			if (1 == sign)
			{
				str[0] = '-';
				++i;
				++dec;
			}
			for (; i<dec; ++i)
			{
				str[i] = string[index++];
			}
			str[i++] = '.';

		}
		else
		{
			if (1 == sign)
			{
				str[0] = '-';
				++i;
			}
			str[++i] = '.';
			i = i - dec + 1;
		}
		for (; i<MAXLINE; ++i)
		{
			str[i] = string[index++];
		}
		str[i] = '\0';
}

